package com.dwj.auto.comment.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.dwj.auto.comment.common.enums.DeleteType;
import com.dwj.auto.comment.common.response.PageResponse;
import com.dwj.auto.comment.common.response.Response;
import com.dwj.auto.comment.common.utils.CodeUtil;
import com.dwj.auto.comment.common.utils.SessionUtil;
import com.dwj.auto.comment.config.mybatis.plus.CommonServiceImpl;
import com.dwj.auto.comment.dao.entity.Role;
import com.dwj.auto.comment.dao.entity.StuClass;
import com.dwj.auto.comment.dao.entity.User;
import com.dwj.auto.comment.dao.entity.UserRole;
import com.dwj.auto.comment.dao.mapper.RoleMapper;
import com.dwj.auto.comment.dao.mapper.StuClassMapper;
import com.dwj.auto.comment.dao.mapper.UserMapper;
import com.dwj.auto.comment.dao.mapper.UserRoleMapper;
import com.dwj.auto.comment.model.form.UserForm;
import com.dwj.auto.comment.model.form.UserLoginForm;
import com.dwj.auto.comment.model.req.StuClassCriteria;
import com.dwj.auto.comment.model.req.UserCriteria;
import com.dwj.auto.comment.model.req.UserRoleSearchCriteria;
import com.dwj.auto.comment.model.vo.StuClassVo;
import com.dwj.auto.comment.model.vo.UserRoleVo;
import com.dwj.auto.comment.model.vo.UserVo;
import com.dwj.auto.comment.service.IUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;

import javax.annotation.Resource;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.dwj.auto.comment.common.constant.RedisKey.User.LOGIN_USER;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author dwjian
 * @since 2020-01-09
 */
@Service
public class UserServiceImpl extends CommonServiceImpl<UserMapper, User> implements IUserService {

    private static final long LOGIN_EXPIRED = 2 * 60 * 60L;

    private static final String TOKEN_KEY = "loginToken";

    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private StuClassMapper stuClassMapper;
    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public Response<User> login(UserLoginForm form) {
        User user = lambdaQuery().eq(User::getUsername, form.getUsername()).eq(User::getIsDel, DeleteType.NO.getValue()).one();
        if (user != null) {
            String password = user.getPassword();
            boolean matches = bCryptPasswordEncoder.matches(form.getPassword(), password);
            if (matches) {
                redisTemplate.delete(LOGIN_USER + user.getLoginToken());
                String loginToken = CodeUtil.uuid();
                user.setLastLoginTime(new Date());
                user.setLoginToken(loginToken);
                baseMapper.updateById(user);
                UserCriteria pagination = new UserCriteria();
                pagination.setUserId(user.getId());
                PageResponse<UserVo> userVoListResp = getList(pagination);
                UserVo userVo = userVoListResp.getData().get(0);
                redisTemplate.opsForValue().set(LOGIN_USER + loginToken, userVo, LOGIN_EXPIRED, TimeUnit.SECONDS);
                SessionUtil.getSession().setAttribute(TOKEN_KEY, loginToken);
                return Response.success(user);
            }
        }
        return Response.fail("用户名或密码错误");
    }

    @Override
    public PageResponse<UserVo> getList(UserCriteria criteria) {
        return PageResponse.success(baseMapper.getList(criteria.buildPage(), criteria));
    }

    @Override
    public Response<String> edit(UserForm form) {
        if (StringUtils.isEmpty(form.getId())) {
            return add(form);
        }
        return Response.success("更新成功");
    }

    @Override
    public Response<UserVo> getByToken(String token) {
        String key = DigestUtils.md5DigestAsHex(token.getBytes());
        Object managerObj = redisTemplate.opsForValue().get(StringUtils.join(LOGIN_USER, key));
        if (managerObj != null) {
            return Response.success(JSONObject.parseObject(JSONObject.toJSONString(managerObj), UserVo.class));
        }
        User user = lambdaQuery().eq(User::getLoginToken, token).eq(User::getIsDel, "0").one();
        UserVo userVo = new UserVo();
        BeanUtils.copyProperties(user, userVo);
        //角色查询
        UserRoleSearchCriteria criteria = new UserRoleSearchCriteria();
        criteria.setUserId(user.getId());
        criteria.setInjectRole(false);
        criteria.setInjectClass(false);
        IPage<UserRoleVo> roleVoPage = userRoleMapper.searchList(criteria.buildPage(), criteria);
        userVo.setUserRole(roleVoPage.getRecords());
        //查询所在班级
        if(!CollectionUtils.isEmpty(roleVoPage.getRecords())){
            List<String> teacherIds = roleVoPage.getRecords().stream().map(UserRoleVo::getId).collect(Collectors.toList());
            StuClassCriteria classCriteria = new StuClassCriteria();
            classCriteria.setLimit(100);
            classCriteria.setInjectRole(false);
            classCriteria.setInjectClass(false);
            classCriteria.setTeacherIds(teacherIds);
            IPage<StuClassVo> classVoPage = stuClassMapper.getList(classCriteria.buildPage(), classCriteria);
            userVo.setUserClass(classVoPage.getRecords());
        }
        redisTemplate.opsForValue().set(StringUtils.join(LOGIN_USER, key), userVo, 2 * 60 * 60L, TimeUnit.SECONDS);
        return Response.success(userVo);
    }

    @Override
    public Response<User> getByUsername(String username) {
        User user = lambdaQuery().eq(User::getUsername, username).eq(User::getIsDel, "0").one();
        return Response.success(user);
    }

    @Override
    public Response<Boolean> resetPassword(String userId, String newPassword) {
        newPassword = bCryptPasswordEncoder.encode(newPassword);
        boolean result = lambdaUpdate().set(newPassword != null && userId != null, User::getPassword, newPassword)
                .eq(User::getStatus, 0).eq(User::getId, userId).eq(User::getIsDel, 0).update();
        return Response.success(result);
    }

    /**
     * 新增用户
     *
     * @param form
     * @return
     */
    private Response<String> add(UserForm form) {
        if (StringUtils.isEmpty(form.getPassword()) || StringUtils.isEmpty(form.getRePassword())
                || !form.getPassword().equals(form.getRePassword())) {
            return Response.fail("两次密码不一致");
        }
        //密码加密
        form.setPassword(bCryptPasswordEncoder.encode(form.getPassword()));
        String userId = CodeUtil.uuid();
        User user = new User();
        BeanUtils.copyProperties(form, user);
        user.setId(userId);
        boolean add = this.save(user);
        if (add) {
            List<String> roleIds = Arrays.asList(form.getRoleIds().split(","));
            List<Role> roleList = roleMapper.selectBatchIds(roleIds);
            roleList.forEach(v -> {
                UserRole userRole = new UserRole();
                String userRoleId = CodeUtil.uuid();
                userRole.setId(userRoleId);
                userRole.setRoleId(v.getId());
                userRole.setRoleName(v.getRoleName());
                userRole.setUserId(userId);
                userRoleMapper.insert(userRole);
                //创建一个默认班级
                StuClass stuClass = new StuClass();
                stuClass.setId(CodeUtil.uuid());
                stuClass.setTeacherId(userRoleId);
                stuClass.setClassName("我的班级");
                stuClass.setTeacherName(user.getUsername());
                stuClassMapper.insert(stuClass);
            });
            return Response.success(0,"新增成功", userId);
        }
        return Response.fail("新增失败");
    }
}
